闲话 22.10.27

闲话

所以就算比赛我写杂题的速度也是两道吗
当然主要是赛后三十分钟改完两道题的原因(

所以今天终于换智能推荐了
【模板】二分图最大匹配【模板】最大流

?没什么好写的
那就写明天的闲话吧

对了我似乎该把闲话归归类了

杂题

AT S8PC3 G

给定 n,m,求斐波那契数列 n 阶前缀和的第 m 项。

n2×105,m1018

不是多项式题。

如果把 n,m 的数据范围换一下这就是大水题了。答案即为

[xm]x(1x)n(1xx2)

随便写点啥都能过吧。

然后解决原问题。这次我们没法简单地通过生成函数得到系数了。当然可能有理展开定理能做,但我没细想。

考虑一手通过通项公式求前缀和表达式。这部分 dirty work,具体看这里
于是我们有一个

i=1nfi=fn+2f2

再化一步,得到

i=1nfi=fn+2(n10)f2

fn 阶前缀和的第 m 项为 dn,m。我们断言,有

dn,m=fm+2(n1)i=0n1(m+i1i)f2(ni1)

证明:
采用数学归纳法。假设对于任意正整数 k<n 有任意 dk,m 满足此公式,我们要证明对于任意 dn,m 也满足。

dn,m=i=1mdn1,i=i=1m(fi+2(n2)j=0n2(i+j1j)f2(nj2))=i=1mfi+2(n2)i=1mj=0n2(i+j1j)f2(nj2)=fm+2(n2)+2f2i=12(n2)fii=1mj=0n2(i+j1j)f2(nj2)=fm+2n2f2f2n2+f2j=0n2(n+jj+1)f2(nj2)=fm+2n2f2n2j=0n2(n+jj+1)f2(nj2)=fm+2n2(n+010)f2(n01)j=1n1(n+j1j)f2(nj1)=fm+2n2j=0n1(n+j1j)f2(nj1)=fm+2(n1)i=0n1(m+i1i)f2(ni1)

证毕。还是很 dirty 的

当然有另一种不化式子的做法,直接生成函数卷出来这个式子。但是没有减号后面的具体形式,需要插出来系数。

啊 第三种是 Bostan-Mori 硬干

code
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define rep(i,a,b) for (register int i = (a), i##_ = (b) + 1; i < i##_; ++i)
#define pre(i,a,b) for (register int i = (a), i##_ = (b) - 1; i > i##_; --i)
const int N = 5e5 + 10, mod = 998244353;
int n, m, fib[N], inv[N], ans;

struct mat {
    int a[2][2];
    mat() { memset(a, 0, sizeof a); };
    
    void I() { memset(a, 0, sizeof a); a[0][0] = a[1][1] = 1; }

    mat operator * (const mat & b) const {
        mat ret; memset(ret.a, 0, sizeof ret.a);
        rep(i,0,1) rep(j,0,1) rep(k,0,1) ret.a[i][j] = (ret.a[i][j] + 1ll * a[i][k] * b.a[k][j] % mod) % mod;
        return ret;
    }
} mt;

mat qp(mat a, int b) {
    mat ret; ret.I();
    while (b) {
        if (b & 1) ret = ret * a;
        a = a * a;
        b >>= 1;
    } return ret;
}

signed main() {
    cin >> n >> m;

    mt.a[0][0] = mt.a[0][1] = mt.a[1][0] = 1; 
    fib[1] = inv[1] = 1;
    rep(i,2,n<<1) fib[i] = (fib[i-1] + fib[i-2]) % mod;
    rep(i,2,n) inv[i] = 1ll * (mod - mod / i) * inv[mod % i] % mod;

    ans = qp(mt, m + 2 * (n - 1)).a[0][1];
    for (int i(0), c(1); i < n; ++ i) {
        ans = (ans - 1ll * c * fib[2 * (n - i - 1)] % mod + mod) % mod;
        c = 1ll * (m + i) % mod * c % mod * inv[i + 1] % mod;
    } 

    cout << ans << endl;
}



P3600 随机数生成器

随机生成一个长度为 n,值域为 [1,x] 的数列,每次询问一个区间 [l,r] 的最小值,最终答案为所有询问的最大值,求答案的期望。对 666623333 取模。

n,x,q2000

如果一个区间被另一个区间完全包含,则包含别人的区间就没有用了,因为它的答案不会更优。
去重后只需要考虑区间有交的情况,且按左端点递增排序。

考虑整数期望公式:

E[x]=i=1i×P[x=i]=i=1i×(P[xi]P[xi+1])=i=1i×P[xi]

考虑如何计算 P[xi]。我们发现,由于是算最小值,可以转化为 1P[x<i] 方便计算。由于答案是各区间最小值的最大值,那就是保证每个询问区间里都存在一个 x<i 的数。

转化区间和元素的关系,我们让元素去找区间。一个元素能覆盖一段区间,覆盖的概率为 p=i1x。我们令 lp[i] 为元素 i 能覆盖的区间中编号最小的编号,rp[i] 为最大编号。
f[i] 为必选值 i,且 1rp[i] 的所有区间都被覆盖的概率。设从 j<i 转移过来,由于都要被覆盖,则需要满足 rp[j]lp[i]1。又,需要考虑不需要覆盖前面部分的情况,有转移

f[i]=p×(rp[j]lp[i]1f[j](1p)ij1+[lp[i]=1](1p)i1)

最后值 i 对答案造成的贡献为

rp[i]=qf[i]×(1p)ni

计算即可。双指针优化 f 的计算,总复杂度 O(n2)

听说 x 能开到 107。我不是很会做法。

code
// for (int j = 1; j <= m; ++ j) fac[i] = 1ll * fac[i-1] * i % mod;
#include <bits/stdc++.h>
using namespace std;
#ifdef ONLINE_JUDGE
    char buf[1<<21], *p1 = buf, *p2 = buf;  inline char getc() { return (p1 == p2 and (p2 = (p1 = buf) + fread(buf, 1, 1<<21, stdin), p1 == p2) ? EOF : *p1++); }
    #define getchar getc
#endif
template <typename T> inline void get(T & x){
	x = 0; char ch = getchar(); bool f = 0; while (ch < '0' or ch > '9') f = f or ch == '-',  ch = getchar();
	while (ch >= '0' and ch <= '9') x = (x<<1) + (x<<3) + (ch^48), ch = getchar(); f and (x = -x);
} template <typename T, typename ... Args> inline void get(T & x, Args & ... _Args) { get(x); get(_Args...); }
#define rep(i,a,b) for (register int i(a), i##_((b) + 1); i < i##_; ++i)
#define pre(i,a,b) for (register int i(a), i##_((b) - 1); i > i##_; --i)
const int N = 3e5 + 10, mod = 666623333;
int n, x, q, ans, stk[N], top, lp[N], rp[N], f[N], inv[N];

struct itv {
	int l, r;
	bool operator < (const itv & b) const { if (l != b.l) return l < b.l; return r > b.r; }
} a[N];
int qp(int a, int b) { int ret = 1; while ( b ) { if (b & 1) ret = 1ll * ret * a % mod; a = 1ll * a * a % mod; b >>= 1;} return ret; }

signed main() {
    get(n, x, q); rep(i,1,q) get(a[i].l, a[i].r);
	sort(a+1, a+1+q);
	
	rep(i,1,q) {
		while (top and a[stk[top]].r >= a[i].r) -- top;
		stk[++top] = i;
	} q = top; rep(i,1,q) a[i] = a[stk[i]];

	for (int i(1), l(1), r(0); i <= n; ++ i) {
		while (r < q and a[r + 1].l <= i) ++ r;
		while (l <= r and a[l].r < i) ++ l;
		lp[i] = l, rp[i] = r;
	}

	rep(t,1,x) {
		int sum = 1, p = 1ll * (t - 1 + mod) * qp(x, mod - 2) % mod, np = (1 - p + mod) % mod;
		int invp = qp(np, mod - 2), nowp = 1;
		inv[0] = f[0] = 1; 
		rep(i,1,n) inv[i] = 1ll * inv[i-1] * invp % mod;
		for (int i(1), j(0); i <= n; ++ i) {
			while (j < i and rp[j] < lp[i] - 1) sum = (sum - 1ll * f[j] * inv[j] % mod + mod) % mod, ++ j;
			f[i] = 1ll * sum * nowp % mod * p % mod; nowp = 1ll * nowp * np % mod;
			sum = (sum + 1ll * f[i] * inv[i]) % mod; 
		}
		int tot = 0; nowp = 1;
		for (int i = n; i; -- i) {
			if (rp[i] != q) break;
			tot = (tot + 1ll * f[i] * nowp) % mod;
			nowp = 1ll * nowp * np % mod;
		}
		ans = (ans + 1 - tot + mod) % mod;
	}
	cout << ans << '\n';
}
posted @   joke3579  阅读(41)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示